﻿using System;
using FourSquare.Domain.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Text;
using FourSquare.Domain.Enums;

namespace FourSquare.Core
{
    public class FourSquareCore
    {
        private string _clientId = "";
        private string _clientSecret = "";
        private string _accessToken = "";
        private APIAccess _apiAccess = new APIAccess();
        private string _fourSqaureVersion= DateTime.Now.ToString("yyyyMMdd");
        private string urlAppender = "";

        public FourSquareCore(string ClientId, string ClientSecret, string AccessToken = "")
        {
            _clientId = ClientId;
            _clientSecret = ClientSecret;
            _accessToken = AccessToken;            
        }

        #region Generic Methods
        private T GetEntity<T>(string result, string token)
        {
            T  obj = default(T);
            Meta meta = _apiAccess.GetMetaResponse(result);
            switch (meta.Code)
            {
                case "200":
                    JToken o = JToken.Parse(result);
                    var parsedToken = o.SelectToken(token);
                    obj = JsonConvert.DeserializeObject<T>(parsedToken.ToString());
                    break;
            }

            return (T)obj;  
        }

        private List<T> GetResultList<T>(string result, string token)
        {
            List<T> listObject = null;
            Meta meta = _apiAccess.GetMetaResponse(result);
            switch (meta.Code)
            {
                case "200":
                    JToken o = JToken.Parse(result);
                    var parsedToken = o.SelectToken(token);

                    listObject = JsonConvert.DeserializeObject<List<T>>(parsedToken.ToString());
                    break;
            }

            return listObject;
        }

        private FourSquareEntityItems<T> GetResultFourSquareEntity<T>(string result, string token)
        {
            FourSquareEntityItems<T> obj = null;
            Meta meta = _apiAccess.GetMetaResponse(result);
            switch (meta.Code)
            {
                case "200":
                    JToken o = JToken.Parse(result);
                    var parsedToken = o.SelectToken(token);

                    obj = JsonConvert.DeserializeObject<FourSquareEntityItems<T>>(parsedToken.ToString());
                    break;
            }

            return obj;
        }

        private FourSquareGroupItems<T> GetResultFourSquareGroupEntity<T>(string result, string token)
        {
            FourSquareGroupItems<T> obj = null;
            Meta meta = _apiAccess.GetMetaResponse(result);
            switch (meta.Code)
            {
                case "200":
                    JToken o = JToken.Parse(result);
                    var parsedToken = o.SelectToken(token);

                    obj = JsonConvert.DeserializeObject<FourSquareGroupItems<T>>(parsedToken.ToString());
                    break;
            }

            return obj;
        }
        #endregion

        #region Venue Methods
        //for documentation go here https://developer.foursquare.com/docs/venues/search
        public Venue GetVenueById(string VenueId)
        {
            _apiAccess.Uri = String.Format("https://api.foursquare.com/v2/venues/{0}?oauth_token={1}&v={2}", VenueId, _accessToken, _fourSqaureVersion);
            string result =_apiAccess.GetResponse();
            return GetEntity<Venue>(result, "response.venue");
        }

        //for documentation go here https://developer.foursquare.com/docs/venues/search
        public List<Venue> GetNearVenue(string venueName, int limit = 10)
        {
            
            _apiAccess.Uri = String.Format("https://api.foursquare.com/v2/venues/search?near={0}&oauth_token={1}&v={2}&limit={3}", venueName, _accessToken, _fourSqaureVersion, limit);
            string result = _apiAccess.GetResponse();

            return GetResultList<Venue>(result, "response.venues");
        }

        //for documentation go here https://developer.foursquare.com/docs/venues/search
        public List<Venue> GetVenueByLatLong(decimal latitude, decimal longitude, int limit = 10)
        {
            _apiAccess.Uri = String.Format("https://api.foursquare.com/v2/venues/search?ll={0},{1}&oauth_token={2}&v={3}&limit={4}", latitude, longitude, _accessToken, _fourSqaureVersion, limit);
            string result = _apiAccess.GetResponse();

            return GetResultList<Venue>(result, "result.venues");

        }

        //for documentation go here https://developer.foursquare.com/docs/venues/tips
        public FourSquareEntityItems<Tip> GetVenueTips(string venueId, Enumerations.Sort sort = Enumerations.Sort.recent, int limit = 10,int offset = 100)
        {
            _apiAccess.Uri = String.Format("https://api.foursquare.com/v2/venues/{0}/tips?sort={1}&limit={2}&offset={3}&oauth_token={4}&v={5}", venueId, sort, limit, offset, _accessToken, _fourSqaureVersion);
            string result = _apiAccess.GetResponse();
            return GetResultFourSquareEntity<Tip>(result, "response.tips");
        }

        public List<Venue> GetVenue(Dictionary<string, string> param)
        {
            if (param.Count > 0)
            {
                StringBuilder uri = new StringBuilder("https://api.foursquare.com/v2/venues/search?");
                foreach (string str in param.Keys)
                {
                    uri.Append(String.Format("{0}={1}&", str, param[str]));
                }

                uri.Append(String.Format("oauth_token={0}&v={1}", _accessToken, _fourSqaureVersion));
                _apiAccess.Uri = uri.ToString();
                string result = _apiAccess.GetResponse();

                return GetResultList<Venue>(result, "response.venues");                
            }
            else
                return null;
        }

        //for documentation go here https://developer.foursquare.com/docs/venues/trending
        public List<Venue> GetTrendingVenue(double latitude, double longitude, int limit = 10, double radius = 5000)
        {
            if (String.IsNullOrEmpty(_accessToken))
                urlAppender = String.Format("client_id={0}&client_secret={1}&v={2}", _clientId, _clientSecret, _fourSqaureVersion);
            else
                urlAppender = String.Format("oauth_token={0}&v={1}", _accessToken, _fourSqaureVersion);


            _apiAccess.Uri = String.Format("https://api.foursquare.com/v2/venues/trending?ll={0},{1}&limit={2}&radius={3}&{4}", latitude, longitude,limit,radius, urlAppender);
            string result = _apiAccess.GetResponse();
            return GetResultList<Venue>(result, "response.venues");
        }

        //for documentation go here https://developer.foursquare.com/docs/venues/explore
        public Explore GetRecommendedAndPopularVenues(string near="", decimal ?latitude = null, decimal ?longitude=null, int limit=10, decimal radius = 250, Enumerations.Section ? section = null, string query = "", Enumerations.FriendVisit ? friendVisit = null,Enumerations.Novelty? novelty = null)
        {
            string ll = "";
            if (latitude != null && longitude != null)
                ll = String.Format("&ll={0},{1}", latitude, longitude);

            _apiAccess.Uri = String.Format("https://api.foursquare.com/v2/venues/explore?&near={0}&limit={1}&radius={2}&section={3}&query={4}&friendVisit={5}&novelty={6}&oauth_token={7}&v={8}{9}", near, limit, radius, section, query, friendVisit, novelty, _accessToken, _fourSqaureVersion, ll);
            string result = _apiAccess.GetResponse();
            return GetEntity<Explore>(result, "response");

        }

        //for documentation go here https://developer.foursquare.com/docs/venues/similar
        public FourSquareEntityItems<Venue> GetSimilarVenue(string venueId)
        {
            _apiAccess.Uri = String.Format("https://api.foursquare.com/v2/venues/{0}/similar?oauth_token={1}&v={2}", venueId, _accessToken, _fourSqaureVersion);
            string result = _apiAccess.GetResponse();

            return GetResultFourSquareEntity<Venue>(result, "response.similarVenues");
        }
        
        //for documentation go here https://developer.foursquare.com/docs/venues/photos
        public FourSquareEntityItems<Photo> GetVenuesPhotos(string venueId)
        {
            if (String.IsNullOrEmpty(_accessToken))
                urlAppender = String.Format("client_id={0}&client_secret={1}&v={2}", _clientId, _clientSecret, _fourSqaureVersion);
            else
                urlAppender = String.Format("oauth_token={0}&v={1}", _accessToken, _fourSqaureVersion);


            _apiAccess.Uri = String.Format("https://api.foursquare.com/v2/venues/{0}/photos?{1}", venueId, urlAppender);
            string result = _apiAccess.GetResponse();
            return GetResultFourSquareEntity<Photo>(result, "response.photos");
        }

        //for documentation go here https://developer.foursquare.com/docs/venues/menu
        public FourSquareEntityItems<Menu> GetVenuesMenu(string venueId)
        {
            if (String.IsNullOrEmpty(_accessToken))
                urlAppender = String.Format("client_id={0}&client_secret={1}&v={2}", _clientId, _clientSecret, _fourSqaureVersion);
            else
                urlAppender = String.Format("oauth_token={0}&v={1}", _accessToken, _fourSqaureVersion);


            _apiAccess.Uri = String.Format("https://api.foursquare.com/v2/venues/{0}/menu?{1}", venueId, urlAppender);
            string result = _apiAccess.GetResponse();
            return GetResultFourSquareEntity<Menu>(result, "response.menu.menus");
        }

        //for documentation go here https://developer.foursquare.com/docs/venues/links
        public FourSquareEntityItems<Link> GetVenueLinks(string venueId)
        {
            if (String.IsNullOrEmpty(_accessToken))
                urlAppender = String.Format("client_id={0}&client_secret={1}&v={2}", _clientId, _clientSecret, _fourSqaureVersion);
            else
                urlAppender = String.Format("oauth_token={0}&v={1}", _accessToken, _fourSqaureVersion);


            _apiAccess.Uri = String.Format("https://api.foursquare.com/v2/venues/{0}/links?{1}", venueId, urlAppender);
            string result = _apiAccess.GetResponse();
            return GetResultFourSquareEntity<Link>(result, "response.links");

        }

        //for documentation go here https://developer.foursquare.com/docs/venues/hours
        public List<WorkingDay> GetWorkingDays(string venueId)
        {
            if (String.IsNullOrEmpty(_accessToken))
                urlAppender = String.Format("client_id={0}&client_secret={1}&v={2}", _clientId, _clientSecret, _fourSqaureVersion);
            else
                urlAppender = String.Format("oauth_token={0}&v={1}", _accessToken, _fourSqaureVersion);


            _apiAccess.Uri = String.Format("https://api.foursquare.com/v2/venues/{0}/hours?{1}", venueId, urlAppender);
            string result = _apiAccess.GetResponse();
            return GetResultList<WorkingDay>(result, "response.hours.timeframes");
        }

        //for documentation go here https://developer.foursquare.com/docs/venues/likes
        public FourSquareGroupItems<User> GetVenueLikes(string venueId)
        {
            if (String.IsNullOrEmpty(_accessToken))
                urlAppender = String.Format("client_id={0}&client_secret={1}&v={2}", _clientId, _clientSecret, _fourSqaureVersion);
            else
                urlAppender = String.Format("oauth_token={0}&v={1}", _accessToken, _fourSqaureVersion);


            _apiAccess.Uri = String.Format("https://api.foursquare.com/v2/venues/{0}/likes?{1}", venueId, urlAppender);
            string result = _apiAccess.GetResponse();
            return GetResultFourSquareGroupEntity<User>(result, "response.likes");
        }

        //for documentation go here https://developer.foursquare.com/docs/venues/like
        public void LikeVenue(string venueId, Enumerations.Likes likes)
        {
            //do later
        }

        #endregion

        #region User Methods
        public User GetUserById(string userId)
        {
            _apiAccess.Uri = String.Format("https://api.foursquare.com/v2/users/{0}?oauth_token={1}&v={2}", userId, _accessToken, _fourSqaureVersion);
            string result = _apiAccess.GetResponse();
            return GetEntity<User>(result, "response.user");
        }

        public List<User> SearchUser(string name ="", string email = "", string twitterSource="",string fbid = "",string twitter ="",string phone ="")
        {
            _apiAccess.Uri = String.Format("https://api.foursquare.com/v2/users/search?name={0}&email={1}&twitterSource={2}&fbid={3}&twitter={4}&phone={5}&oauth_token={6}&v={7}", name, email, twitterSource, fbid, twitter, phone, _accessToken, _fourSqaureVersion);
            string result = _apiAccess.GetResponse();
            return GetResultList<User>(result, "response.results");
        }
        #endregion

        #region Checkin

        public void CheckIn(string venueId)
        {
            _apiAccess.Uri = "https://api.foursquare.com/v2/checkins/add?venueId=4fc22484e4b03f9cf9fc7d48&oauth_token=ZTEHHIIFIAL40H4RMHDZKXBYTNSLNMVOTDEVXCDEESLBINOQ&v=20121120";
            _apiAccess.PostAction();
        }

        #endregion

    }
}
